#include <iostream>
#include <unistd.h>
#include <cstdlib>
#include <cassert>
#include <string>
#include <vector>
#include <ctime>
#include <sys/wait.h>
#include <sys/types.h>




#define MakeSeed() srand((unsigned long)time(nullptr)^ getpid() ^ 0x171313 ^ rand()%1234)
#define PROCESS_NUM 5
//------------------------------子进程要完成的某种任务-------------------------------------------------------------
//函数指针 类型
typedef void(*func_t)();
void downLoadTask()
{
    std::cout << getpid() << ": 下载任务\n" << std::endl;
    sleep(1);//模拟下载任务
}
void ioTask()
{
    std::cout << getpid() << ": IO任务\n" << std::endl;
    sleep(1);//模拟IO任务
}
void flushTask()
{
    std::cout << getpid() << ": 刷新任务\n" << std::endl;
    sleep(1);//模拟刷新任务
}
//任务表
void loadTaskFunc(std::vector<func_t>* funcMap)
{
    funcMap->push_back(downLoadTask);
    funcMap->push_back(ioTask);
    funcMap->push_back(flushTask);
}

//-----------------------------下面的代码是一个多进程程序----------------------------------------------------------
class SubEp //end point
{
public:
    SubEp(pid_t subId,int writeFd)
    :_subId(subId),_writeFd(writeFd)
    {
        char nameBuffer[1024];
        snprintf(nameBuffer,sizeof nameBuffer,"process-%d[pid(%d)-fd(%d)]",num++,_subId,_writeFd);
        _name = nameBuffer;
    }

public:
    std::string _name;
    pid_t _subId;
    int _writeFd;
    static int num;
};
int SubEp::num = 0;
//获取命令码
int recvTask(int readFd)
{
    int code = 0;
    ssize_t s = read(readFd, &code, sizeof code);
    if(s == 4) 
        return code;
    else
        return -1;;
}
//发送任务给进程
void sendTask(const SubEp& process,int taskNum)
{
    std::cout << "send task num: "<< taskNum << " send to -> " << process._name << std::endl;
    int n = write(process._writeFd,&taskNum,sizeof(taskNum));
    assert(n == sizeof(int));
    (void)n;
}
//创建子进程，建立父子通信信道
void creatSubProcess(std::vector<SubEp>* subs,std::vector<func_t>& funcMap)
{
    for(int i = 0; i < PROCESS_NUM;++i)
    {
        int fds[2];
        int n = pipe(fds);
        assert(n == 0);
        (void)n;

        pid_t id = fork();
        if(id == 0)
        {
            //子进程进行处理任务
            close(fds[1]);
            while(true)
            {
                //1. 获取命令码，如果没有发送，子进程应该阻塞
                int commandCode = recvTask(fds[0]);
                //2. 完成任务
                if(commandCode >= 0 && commandCode < funcMap.size())
                    funcMap[commandCode]();
                else if(commandCode == -1)
                    break;
            }
            exit(0);
        }
        close(fds[0]);
        SubEp sub(id,fds[1]);
        subs->push_back(sub);
    }
}
//让随机一个子进程完成随机任务
void loadBlanceContrl(const std::vector<SubEp>& subs,const std::vector<func_t>& funcMap,int count)
{
    int processNum = subs.size();
    int taskNum = funcMap.size();
    
    while(true)
    {
        //1. 选择一个子进程
        int subIndex = rand()% processNum;
        //2. 选择一个任务
        int taskIndex = rand()% taskNum;
        //3. 任务发送给选择的进程
        sendTask(subs[subIndex],taskIndex);
        sleep(1);
        if(count != 0)
        {
            --count;
            if(count == 0) break;
        }
    }
    //关闭子进程文件描述符中的写端
    for(int i = 0;i < processNum;++i)
        close(subs[i]._writeFd);
}
//回收子进程
void waitProcess(const std::vector<SubEp>& processes)
{
    int processNum = processes.size();

    for(int i = 0; i < processNum;++i)
    {
        waitpid(processes[i]._subId,nullptr,0);
        std::cout<< "wait sub process success ..."<< processes[i]._subId << std::endl;
    }
}

int main()
{
    MakeSeed();
    //1.建立子进程并且建立和子进程通信的信道
    // 加载方法表
    std::vector<func_t> funcMap;
    loadTaskFunc(&funcMap);
    //创建子进程，并维护好父子通信信道
    std::vector<SubEp> subs;
    creatSubProcess(&subs,funcMap);
    //2.走到这就是父进程，控制子进程，负载均衡的向子进程发送命令码
    int taskCnt = 5;    // = 0 ：表示永远进行
    loadBlanceContrl(subs,funcMap,taskCnt);
    

    //3. 回收子进程信息
    waitProcess(subs);
    return 0;
}